Release 10.1A: OpenEdge Development:
Progress Dynamics Advanced Development


Starting Progress Dynamics application windows

When you create a static SmartWindow in the AppBuilder and drop objects onto it, the AppBuilder generates a procedure called adm-create-objects to create all of those objects at run time. In Progress Dynamics, most windows are dynamic objects, so one dynamic window procedure, rydyncontw.w, has an empty version of adm-create-objects that acts like a placeholder. The procedure calls to create the window, and its contents are executed at run time rather than being pregenerated into a source code file. The sequence of steps that occurs and the procedures that are run remain the same as for static windows. The adm-create-objects procedure retains the older naming style of adm- plus a procedure name from an older version of the ADM. The reason for this is that in static windows, we need to allow for the AppBuilder-generated code, which the developer should not edit directly, plus a possible local override procedure that can do additional work when objects are created. Because these are both in the same source procedure in a static environment, they must have different names.

As a result, the actual ADM event that is run in a container and published in any child containers is createobjects. The standard code for createobjects, found in the super procedure containr.p, runs adm-create-objects, which executes the AppBuilder-generated code for a static window. If the developer wants to write custom code for this stage of the application, this goes into a local version of the createobjects procedure, as shown:

Procedure createobjects: 
  Parameters:  <none> 
Candidate for: localization 
  See below for information on creating a local version of createobjects 

Here is an excerpt from an AppBuilder-generated adm-create-objects procedure that serves as a model for running some of the same support procedures in your own code:

PROCEDURE adm-create-objects: 
/*-------------------------------------------------------------- 
Purpose:      
Create handles for all Smartobjects used in this procedure.  
After Smartobjects are initialized, then SmartLinks are added. 
Parameters:  <none> 
----------------------------------------------------------------*/ 
  DEFINE VARIABLE currentPage  AS INTEGER NO-UNDO. 
  ASSIGN currentPage = getCurrentPage(). 
  CASE currentPage: 
    WHEN 0 THEN DO: 
       RUN constructObject ( 
             INPUT  'adm2/pnavlbl.w':U , 
             INPUT  FRAME fMain:HANDLE , 
             INPUT  
'EdgePixels_2_PanelType_Nav-Label_HideOnInit_no_DisableOnInit_no_ObjectLayou
t_':U , 
             OUTPUT h_pnavlbl ). 
       RUN repositionObject IN h_pnavlbl ( 1.71 , 22.00 ) NO-ERROR. 
       RUN resizeObject IN h_pnavlbl ( 1.76 , 34.00 ) NO-ERROR.  
RUN constructObject ( 
             INPUT  'dcust.w_DB-AWARE':U , 
             INPUT  FRAME fMain:HANDLE ,  
INPUT 
'AppService__ASUsePrompt__ASInfo__ForeignFields__RowsToBatch_2_CheckCurrentC
hanged_yes_RebuildOnRepos_no_ServerOperatingMode_NONE_DestroyStateless_no_Di
sconnectAppServer_no':U , 
             OUTPUT h_dcust ). 
       RUN repositionObject IN h_dcust ( 1.95 , 6.00 ) NO-ERROR. 
       /* Size in AB:  ( 1.86 , 10.80 ) */ 
       RUN constructObject ( 
             INPUT  'adm2/pupdsav.w':U , 
             INPUT  FRAME fMain:HANDLE , 
             INPUT  
'AddFunction_One-Record_EdgePixels_2_PanelType_Save_HideOnInit_no_DisableOnI
nit_no_ObjectLayout_':U , 
             OUTPUT h_pupdsav ). 
       RUN repositionObject IN h_pupdsav ( 4.33 , 20.00 ) NO-ERROR. 
       RUN resizeObject IN h_pupdsav ( 1.76 , 56.00 ) NO-ERROR. 
       RUN constructObject ( 
             INPUT  'vcust.w':U , 
             INPUT  FRAME fMain:HANDLE , 
             INPUT  'HideOnInit_no_DisableOnInit_no_ObjectLayout_':U , 
OUTPUT h_vcust ). 
       RUN repositionObject IN h_vcust ( 7.91 , 4.00 ) NO-ERROR. 
       /* Size in AB:  ( 6.86 , 66.00 ) */ 
       /* Links to SmartDataObject h_dcust. */ 
       RUN addLink ( h_pnavlbl , 'Navigation':U , h_dcust ). 
       /* Links to SmartDataViewer h_vcust. */ 
       RUN addLink ( h_dcust , 'Data':U , h_vcust ). 
RUN addLink ( h_vcust , 'Update':U , h_dcust ). 
       RUN addLink ( h_pupdsav , 'TableIO':U , h_vcust ). 
/* Adjust the tab order of the smart objects. */ 
       RUN adjustTabOrder ( h_pupdsav , 
             h_pnavlbl , 'AFTER':U ). 
       RUN adjustTabOrder ( h_vcust , 
             h_pupdsav , 'AFTER':U ). 
    END. /* Page 0 */ 
END CASE. 
END PROCEDURE. 

The static adm-create-objects procedure, or the createobjects code for dynamic windows, does several things. First, for each SmartObject in the container, it runs constructObject, which takes the SmartObject procedure name, its parent Frame handle, and its list of instance property settings as INPUT parameters, and returns the procedure handle of the new SmartObject as an OUTPUT parameter. The constructObject procedure runs the SmartObject as a persistent procedure, parents its default frame (if any) to the frame handle passed in, and runs the set<property> function for each instance property name/value pair passed in. Instance properties are SmartObject properties for which initial values can be defined for a particular instance of the object as used in some container. These properties can be set in the Instance Property dialog box of the SmartObject as the container is assembled, and they are initialized in the following example:

Procedure constructObject: 
Parameters: 
    (INPUT pcProcName /* CHARACTER -- SmartObject name */, 
     INPUT phParent   /* HANDLE -- parent Frame handle */, 
     INPUT pcPropList /* CHARACTER -- Instance Properties */, 
     OUTPUT phObject  /* HANDLE -- new procedure handle */). 
Candidate for: calling 
  You can call constructObject from your own code to create additional objects 
in a window at runtime based on application-specific or user-specific factors. 

The procedure handle of the new SmartObject instance is returned to adm-create-objects, which uses it in several other procedure calls.

For any SmartObject with a visualization, repositionObject is run to position it at run time. Also, for any object that is resizable, resizeObject is run to size the object appropriately. The presence of the resizeObject procedure in the object (or its super procedures) determines whether it should be made resizable. In Progress Dynamics, of course, object positions and sizes are not fixed at design time. The layout manager determines the sizes and relative positions of objects based on the overall window size and on which objects are resizable. But you can use these procedures where needed in your code to adjust sizes and position, as shown:

Procedure repositionObject: 
  Parameters: 
    (INPUT pdRow /* DECIMAL – Row number */, 
     INPUT pdCol /* DECIMAL – Column number */). 
Candidate for: calling 

You could run repositionobject from your code to adjust default object positions or to position objects you created outside the window definition stored in the Repository, as shown:

Procedure resizeObject: 
  Parameters: 
    (INPUT pd_height /* DECIMAL – height in Rows*/, 
     INPUT pd_width /* DECIMAL – width in Characters */). 
Candidate for: calling 

You could resize an object based on application requirements, or to make adjustments outside the standard layout manager support.

Once all the SmartObjects have been created, any SmartLinks between those objects are defined. Use the addLink procedure to do this. This is described in the "Managing links in Progress Dynamics applications" section.

The AppBuilder also generates calls to adjustTabOrder to assure that the tabbing order between SmartObjects is either left-to-right/top-to-bottom (the default), or as reset by the developer in the AppBuilder, as shown:

Procedure adjustTabOrder: 
  Parameters: 
    (INPUT phObject /* HANDLE – object to re-order */, 
     INPUT phAnchor /* HANDLE – object to re-order relative to */, 
     INPUT pcPosition /* CHARACTER – move “BEFORE” or “AFTER”*/). 
Candidate for: calling 
  Your code can adjust tab order based on user preferences or application 
specific requirements. 

There are two additional properties that are used in Progress Dynamics to size objects proportionally in dynamic windows, resizeHorizontal and resizeVertical. The LOGICAL properties indicate whether a visual object can be resized in one dimension or the other or both when the window is initially sized, or when it is resized by a user. The properties are defined for all visual objects and have the default values shown in Table 5–1.

Table 5–1: Default values of resize properties for visual objects
Object
resizeHorizontal properties
resizeVertical properties
Viewer
FALSE
FALSE
Browser
TRUE
TRUE
Window
TRUE
TRUE
Toolbar
TRUE
FALSE

Note that you can override these default values. You can set these properties for individual objects to change the default resizing, for example, if you want a browser to be a fixed size in one or both dimensions.

You can set these properties in the Container Builder in the instance section of the main window.

Now, when you run the Customer browse window, the browser is a fixed height, as you can see in Figure 5–2.

Figure 5–2: Customer selection window

The createobjects and adm-create-objects procedures are part of a sequence that occurs when a container is run. It’s important to know the steps in this sequence and where the appropriate places are to put custom application code.

When you run SmartObject code from constructObject, any code in its main block is executed first. Custom code that should be executed as soon as the object is run, before anything else happens, can be placed in the main block. Remember that at this time the object has no links to other objects, so you cannot refer to its Data-Source or other such connections; its instance property values also are not yet set, so you cannot refer to them. If you try to set them, the values set by the container override your settings. If you create static objects and need code to be executed immediately when the object is run, you can put it in the main block (this is true for any persistent procedure). If you’re using dynamic objects, then you’ll have to write a super procedure where you override standard procedures or respond to events.

For the remainder of this chapter, assume that any references to local application code should be taken to mean either code written in a static SmartObject procedure or (preferably in most cases) code written into a custom super procedure for a dynamic object.

Custom code for a window that must reference its contained SmartObjects as soon as they are created should go into a local createobjects procedure. If you look at the same adm-create-objects procedure above, note that it references the CurrentPage property, and then executes a block of a CASE statement depending on the current page number. When the window is first run, its CurrentPage is zero. As each additional page (if any) is first referenced, createobjects and adm-create-objects are run again to create the objects on that page.

If you define a local createObjects procedure, remember that it runs multiple times if the window has more than just the default page zero, so check the ObjectCreated property. It will be false the first time and true on each subsequent call. You can also check the CurrentPage property in the same way that adm-create-objects does. Each CASE should contain a RUN SUPER statement to invoke the code in adm-create-objects for that page, with the custom code added either before or after that statement, as appropriate.

Code that must do something immediately before the objects on a page are created can be placed in createobjects before the RUN SUPER statement for that page. Code that must be executed after the objects are created (which seems more likely, since, of course, you cannot access the objects on a page before they are run) must be written after the RUN SUPER statement for that CASE. For example, a createobjects procedure can add additional links between objects that have just been created (based on dynamic application requirements); or it can set additional property values that are not instance properties or that must be set conditionally based on application requirements; it might reposition or reorder objects; or other such things. At this point in the window’s life, all the objects on the current page have been created, positioned, and resized; their frame handles have been parented to the window’s frame; their instance property values have been set; and their links and tab order have been established. But they have not been initialized; that is, the initializeObject event procedure has not been run, so visual objects have not been viewed or enabled; queries have not been opened, and so on.


Copyright © 2005 Progress Software Corporation
www.progress.com
Voice: (781) 280-4000
Fax: (781) 280-4095